home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / blix / maze.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  35.5 KB  |  1,438 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*_________________________________________________________________________
  18.  |
  19.  | maze.c - maze creation and drawing routines
  20.  |
  21.  | 
  22.  | init_maze()    used to read the maze data from the file maze.dat
  23.  | build_maze()    builds the objects from the data
  24.  | draw_maze()    draws the maze for you by calling all its objects
  25.  | free_arcs()    deletes the generated objects for the active level
  26.  | 
  27.  | the maze itself is a nested structure of type maze_t defined in maze.h
  28.  |
  29.  |     (c) 1994 Frans van Hoesel, Xtreme graphics software
  30.  |
  31. */
  32.  
  33.  
  34.  
  35. #include <alloca.h>
  36. #include <gl/gl.h>
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <math.h>
  40. #include <fcntl.h>
  41. #include <string.h>
  42. #include <bstring.h>
  43. #include <ctype.h>
  44. #include <stdarg.h>
  45. #include "config.h"
  46. #include "io.h"
  47. #include "blixvect.h"
  48. #include "lod.h"
  49. #include "maze.h"
  50. #include "mymath.h"
  51. #include "rand.h"
  52. #include "blixsound.h"
  53.  
  54. /*_________________________________________________________________________
  55.  |
  56.  | static variables and constants used while reading the maze.dat data file
  57.  | 
  58. */
  59.  
  60. #define MAXLEVEL 5
  61. #define MAXCENTER 20
  62. #define MAXCIRCLE 10
  63. #define MAXNODES 1600
  64. #define MAXARC 20
  65.  
  66. /* local typedefs and declarations */
  67.  
  68. static int read_maze(maze_t *maze);
  69. static int read_level(level_t *level);
  70. static int read_center(center_t *center);
  71. static int read_circle(circle_t *circle);
  72. static void read_nodes(node_t *nodes);
  73. static int read_node(node_t *node);
  74. static void free_maze(maze_t *maze);
  75. static void connect_nodes(const int n1, const int n2);
  76.  
  77. #ifdef BUILDNODES
  78. static void build_nodes(node_t *nodes);
  79. static int add_node(const float *p, const int num);
  80. static int check_node(float p[3], Matrix *m, int cent);
  81. #endif
  82.  
  83. /* static variables */
  84. static Object lastobject = 0;
  85.  
  86. extern int can_do_textures;
  87. extern int Lod;
  88. maze_t the_maze;
  89. level_t the_level;
  90. node_t *the_nodes;
  91. int the_nnodes;
  92. /*________________________________________________________________________
  93.  |
  94.  | init_maze - public functiona that reads maze data from file
  95.  |
  96.  | call this before you try to do anything else with the maze
  97. */
  98.  
  99. void init_maze(void) {
  100.     read_maze(& the_maze);
  101. }
  102.  
  103. /*________________________________________________________________________
  104.  |
  105.  | read_maze - read maze data from file
  106.  |
  107.  | it opens the file "maze.dat" then repeatedly calls read_level,
  108.  | until that function returns
  109.  | EOF
  110. */
  111.  
  112.  
  113. static int read_maze(maze_t *maze) {
  114.  
  115.     level_t this_level;
  116.     level_t *level_ptr;
  117.     int cnt = 0;
  118.     center_t these_centers[MAXCENTER];
  119.     node_t these_nodes[MAXNODES];
  120.     static int read_before = FALSE;
  121.     
  122.     
  123.     if (read_before == TRUE) {
  124.     /* free allocated memory and delete related GL-objects */
  125.     free_maze(maze);
  126.     }
  127.     the_nnodes = 0;
  128.     
  129.     read_before = TRUE;
  130.     this_level.ncenters = 0;
  131.     this_level.centers = these_centers;
  132.     this_level.nodes = these_nodes;
  133.     
  134.     open_file("maze.dat");
  135.     read_before = TRUE;
  136.     maze->levels = (level_t *)malloc(MAXLEVEL * sizeof(level_t));
  137.     skipblanks();
  138.     level_ptr =  maze->levels;
  139.     maze->nlevels = 0;
  140.     while (cnt++ < MAXLEVEL && read_level(&this_level) != EOF) {
  141.     /* check that levels are specified in order */
  142.     if (this_level.leveln != cnt)
  143.         errormsg("levels must be specifies in order");
  144.     maze->nlevels += 1;
  145.     
  146.     /* copy level, but don't allocate more then really needed */
  147.     *level_ptr = this_level;
  148.     level_ptr->centers = (center_t *)malloc(this_level.ncenters *
  149.         sizeof(center_t));
  150.     bcopy(this_level.centers, level_ptr->centers, 
  151.         this_level.ncenters * sizeof(center_t));
  152.     level_ptr->nodes = (node_t *)malloc(this_level.nnodes *
  153.         sizeof(node_t));
  154.     bcopy(this_level.nodes, level_ptr->nodes, this_level.nnodes *
  155.         sizeof(node_t));
  156.     the_nodes = level_ptr->nodes;
  157.     level_ptr++;
  158.     }
  159.     close_file();
  160.     
  161.     return 0;
  162. }
  163.  
  164. /*________________________________________________________________________
  165.  |
  166.  | read_level - read a level from file
  167.  |
  168.  | Reads a level by reading one center in a local declared center
  169.  | (this_center) and then malloc the space needed to add it to the level
  170.  | structure. Repead that until the read_center function fails.
  171. */
  172.  
  173. static int read_level (level_t *level) {
  174.  
  175.     center_t this_center;
  176.     center_t *center_ptr;
  177.     int cnt = 0;
  178.     circle_t these_circles[MAXCIRCLE];
  179.  
  180.     this_center.ncircles = 0;
  181.     this_center.circles = these_circles; 
  182.     if (read_str("level"))
  183.     return EOF;
  184.     expect_ch('(');
  185.     if (test_ch(')')==0) {
  186.     /* accept the integer indicating the level, but ignore it 
  187.      * Levels must be specified in order.
  188.      */    
  189.     level->leveln  = accept_int();
  190.     }
  191.     expect_ch(')');
  192.     expect_ch(';');        
  193.     center_ptr = level->centers;
  194.     level->ncenters = 0;
  195.     while (cnt++ < MAXCENTER && read_center(&this_center) != EOF) {
  196.     level->ncenters += 1;
  197.     
  198.     /* copy center, but don't allocate more then really needed */
  199.     *center_ptr = this_center;
  200.     center_ptr->circles = (circle_t *)malloc(this_center.ncircles *
  201.         sizeof(circle_t));
  202.     bcopy(this_center.circles, center_ptr->circles, 
  203.         this_center.ncircles * sizeof(circle_t));
  204.     center_ptr->radius =
  205.         this_center.circles[this_center.ncircles-1].cradius;
  206.     center_ptr++;
  207.     }
  208.     the_nnodes = 0;
  209.     the_nodes = level->nodes;
  210.     the_level = *level;
  211.     read_nodes(the_nodes);
  212. /*
  213. #   ifdef BUILDNODES
  214.     the_nnodes = 0;
  215.     build_nodes(the_nodes);
  216. #   endif
  217. */
  218.     level->nnodes = the_nnodes;
  219.     return 0;
  220. }
  221.  
  222. static void read_nodes(node_t *nodes) {
  223.     the_nnodes = 0;
  224.     while (the_nnodes < MAXNODES && read_node(nodes) != EOF) {
  225.     nodes++;
  226.     the_nnodes++;
  227.     }
  228. }
  229.         
  230. static int read_node(node_t *node) {
  231.     int i;
  232.     int nodenum, connect;
  233.     skipblanks();
  234.  
  235.     if (read_str("node")) {
  236.     return EOF;
  237.     }
  238.     expect_ch('(');
  239.     nodenum = accept_int();
  240.     expect_ch(',');
  241.     i = accept_int();
  242.     node->special.all = 0;
  243.     if (i & 0x10 ) {
  244.     node->special.b.ndir = 1;
  245.     node->special.b.ptype = i & 0x0f;
  246.     } else {
  247.     node->special.b.ptype = i & 0x0f;
  248.     }
  249.     node->special.b.magic = (i & 0xfffff00) >> 8;
  250.     expect_ch(',');
  251.     node->pos[0] = accept_float();
  252.     expect_ch(',');
  253.     node->pos[1] = accept_float();
  254.     expect_ch(',');
  255.     node->pos[2] = accept_float();
  256.     vnormal(node->pos);
  257.     i = 0;
  258.     skipblanks();
  259.     while (test_ch(')')==0 && i < 4) {
  260.     expect_ch(',');
  261.     connect = accept_int();
  262.     (node->c)[i] = connect;
  263.     if (connect < nodenum)
  264.         connect_nodes(connect, nodenum);
  265.     i++;
  266.     }
  267.     node->cnt = i;
  268.     while (i < 4) {
  269.     (node->c)[i] = -1;
  270.     i++;
  271.     }
  272.     expect_ch(')');
  273.     expect_ch(';');
  274.     return 0;
  275. }
  276.  
  277.         
  278. static int read_center (center_t *center) {
  279.  
  280.     circle_t this_circle;
  281.     circle_t *circle_ptr;
  282.     int cnt = 0;
  283.     float rotation;
  284.     arc_t these_arcs[MAXARC];
  285.     float these_walls[MAXARC];
  286.     float these_gaps[MAXARC];
  287.     int    these_cappings[MAXARC];
  288.  
  289.     this_circle.narcs = 0;
  290.     this_circle.arcs = these_arcs;
  291.     this_circle.walls = these_walls;
  292.     this_circle.gaps = these_gaps;
  293.     this_circle.cappings = these_cappings;
  294.  
  295.     skipblanks();
  296.     if (read_str("center"))
  297.     return EOF;
  298.     expect_ch('(');
  299.     center->center_v[0] = accept_float();
  300.     expect_ch(',');
  301.     center->center_v[1] = accept_float();
  302.     expect_ch(',');
  303.     center->center_v[2] = accept_float();
  304.     expect_ch(',');
  305.     center->axis_v[0] = accept_float();
  306.     expect_ch(',');
  307.     center->axis_v[1] = accept_float();
  308.     expect_ch(',');
  309.     center->axis_v[2] = accept_float();
  310.     expect_ch(')');
  311.     expect_ch(';');        
  312.     circle_ptr = center->circles;
  313.     center->ncircles = 0;
  314.     while (cnt++ < MAXCENTER && read_circle(&this_circle) != EOF) {
  315.     center->ncircles += 1;    
  316.     /* copy circle, but don't allocate more then really needed */    
  317.     *circle_ptr = this_circle;
  318.     circle_ptr->arcs = (arc_t *)malloc(this_circle.narcs * sizeof(arc_t));
  319.     circle_ptr->walls = (float *)malloc(this_circle.narcs * sizeof(float));
  320.     circle_ptr->gaps = (float *)malloc(this_circle.narcs * sizeof(float));
  321.     circle_ptr->cappings = (int *)malloc(this_circle.narcs * sizeof(int));
  322.     bcopy(this_circle.arcs, circle_ptr->arcs, 
  323.         this_circle.narcs * sizeof(arc_t));
  324.     bcopy(this_circle.walls, circle_ptr->walls, 
  325.         this_circle.narcs * sizeof(float));
  326.     bcopy(this_circle.gaps, circle_ptr->gaps, 
  327.         this_circle.narcs * sizeof(float));
  328.     bcopy(this_circle.cappings, circle_ptr->cappings, 
  329.         this_circle.narcs * sizeof(int));
  330.     /* find its cartesian radius */
  331.     rotation = this_circle.start[0];
  332.     vrot_axis(center->center_v, center->axis_v,
  333.         (center->ncircles-1+0.4508) * PI_DEPTH, circle_ptr->start);
  334.     vrot_axis(circle_ptr->start, center->center_v, 
  335.         rotation , circle_ptr->start);
  336.  
  337.     circle_ptr->cradius = vdistance(circle_ptr->start, center->center_v); 
  338.  
  339.     circle_ptr++;
  340.     }
  341.     return 0;
  342. }
  343.     
  344.  
  345. static int read_circle (circle_t *circle) {
  346.  
  347.     float *wall_ptr;
  348.     float *gap_ptr;
  349.     int *capping_ptr;
  350.  
  351.     int cnt = 0;
  352.  
  353.     float total_angle = 0;
  354.  
  355.     skipblanks();
  356.     if (read_str("circle"))
  357.     return EOF;
  358.     expect_ch('(');
  359.     /* store the overall rotation temporarely in start[0]; the actual
  360.      * starting point wich results from this is calculated in the calling
  361.      * function read_center()
  362.      */
  363.     circle->start[0] = accept_float();
  364.     wall_ptr = circle->walls;
  365.     gap_ptr = circle->gaps;
  366.     capping_ptr = circle->cappings;
  367.     circle->narcs = 0;
  368.     do {
  369.     skipblanks();
  370.     if (read_ch('|') == 0) {
  371.         *capping_ptr = 1;
  372.     } else if (read_ch(',') == 0) {
  373.         *capping_ptr = 0;
  374.     } else 
  375.         errormsg("comma or '|' expected");
  376.     *wall_ptr = accept_float();
  377.     skipblanks();
  378.     if (read_ch('|') == 0) {
  379.         *capping_ptr |= 2;
  380.     } else if (read_ch(',') == 0) {
  381.         ;
  382.     } else 
  383.         errormsg("comma or '|' expected");
  384.     *gap_ptr = accept_float();
  385.     circle->narcs += 1;
  386.     total_angle += *wall_ptr + *gap_ptr;
  387.     wall_ptr++;
  388.     gap_ptr++;
  389.     capping_ptr++;
  390.     skipblanks();
  391.     } while (++cnt < MAXARC && read_ch(')'));
  392.     if (fabs (PI2 -total_angle) > 0.1) {
  393.     warningmsg(" angles don't add up "
  394.         "to 2 * pi (%f).\n", total_angle);
  395.     }
  396.     *(circle->walls) = PI2 - total_angle + *(circle->walls); 
  397.     expect_ch(';');        
  398.     return 0;
  399. }
  400.     
  401.  
  402. /*____________________________________________________________________________
  403.  |
  404.  | build_arc - create a gl object for the walls
  405.  |
  406.  | if you want different walls, change that here.
  407.  |
  408. */
  409.  
  410. static void build_arc(const float center[3], const float start[3],
  411.     float stepangle, const float angle, int cap, int lod, arc_t *w,
  412.     float end[3]) {
  413.     
  414. #define MAXSEG 85
  415.  
  416.     segment_t *s, *sprev;
  417.     segment_t seg[MAXSEG];
  418.  
  419.     float t1[3], t2[3], wd[3];
  420.     float st[2];
  421.     Matrix m;
  422.     int nstep, i, j;
  423.     
  424.     nstep = (int) (angle / stepangle );
  425.     if (nstep == 0) 
  426.     nstep = 1;
  427.     if (nstep >= MAXSEG -1) {
  428.      printf("too many segments\n");
  429.      exit(1);
  430.     }
  431.     s = seg;
  432.  
  433.     mmake_rot_axis(center, -angle/ nstep, m);
  434.     vcopy(start, end);
  435.     vcross(start, center, t1);
  436.     vcross(start, t1, t2);
  437.     vnormal(t2);
  438.     vcopy(t2, wd);
  439.     vcopy(wd, s->n0);
  440.     vcopy(wd, s->n2);
  441.     vscalar(s->n2, -1.0);
  442.     vscalar(wd, WIDTH / 2.0);
  443.     if (lod >= WALLS_UP) {
  444.     vcopy(start, t1);
  445.     vscalar(t1, 0.989);
  446.     vadd(t1, wd, s->w0);
  447.     vsub(t1, wd, s->w1);
  448.     } else {
  449.     vadd(start, wd, s->w0);
  450.     vsub(start, wd, s->w1);
  451.     }
  452.     vcopy(start, s->n1);
  453.     vcopy(start, t1);
  454.     vscalar(t1, 1.0 + MAXHEIGHT);
  455.     vadd(t1, wd, s->w2);
  456.     vsub(t1, wd, s->w3);
  457.  
  458.     /* tilt the normal a bit so we get some more light in the scene */
  459.     vcopy(s->n1, t1);
  460.     vscalar(t1, 0.1);
  461.     vadd(s->n0, t1, s->n0);
  462.     vnormal(s->n0);
  463.     vadd(s->n2, t1, s->n2);
  464.     vnormal(s->n2);
  465.  
  466.      
  467.     sprev = s;
  468.     s++;
  469.     for (i=1; i <= nstep; i++) {
  470.     vtransform(end, m, end);
  471.     vtransform(sprev->w0, m, s->w0);
  472.     vtransform(sprev->w1, m, s->w1);
  473.     vtransform(sprev->n1, m, s->n1);
  474.     if (lod >= WALLS_UP) {
  475.         vtransform(sprev->w2, m, s->w2);
  476.         vtransform(sprev->w3, m, s->w3);
  477.         vtransform(sprev->n0, m, s->n0);
  478.         vtransform(sprev->n2, m, s->n2);
  479.     }
  480.     sprev = s;
  481.     s++;
  482.     }
  483.     s = seg;
  484.     if (lod >= WALLS_UP) {
  485.     lastobject++;
  486.     w->wall_obj = lastobject;
  487.     makeobj(w->wall_obj);
  488.     /*cpack(0x00012488);*/
  489.     bgnqstrip();
  490.         /* inside wall */
  491.         for (j =0; j<= nstep; j++) {
  492.         n3f(s->n0);
  493.         if (lod >= TEXTURE_MAPS && can_do_textures) {
  494.         if (lod >= EXTRA_FINE) {
  495.             st[0] = j * 0.4;
  496.         } else {
  497.             st[0] = j * 1.2;
  498.         }
  499.         st[1] = 0;
  500.         t2f(st);
  501.         v3f(s->w2);
  502.         st[1] = 1;
  503.         t2f(st);
  504.         } else {
  505.         v3f(s->w2);
  506.         }
  507.         v3f(s->w0);
  508.         s++;
  509.         }
  510.         endqstrip();
  511.  
  512.     s = seg;
  513.     /* starting cap */
  514.     if (cap & 1) {
  515.         /* put cap on starting segment of wall */
  516.         vsub(s->w0, (s+1)->w0, t1);
  517.         vnormal(t1); /* this is the approximate normal */
  518.         bgnqstrip();
  519.         n3f(t1);
  520.         v3f(s->w2);
  521.         v3f(s->w3);
  522.         v3f(s->w0);
  523.         v3f(s->w1);
  524.         endqstrip();
  525.     }
  526.  
  527.     /* outside wall */
  528.     bgnqstrip();
  529.     for (j =0; j<= nstep; j++) {
  530.         n3f(s->n2);
  531.         if (lod >= TEXTURE_MAPS && can_do_textures) {
  532.         if (lod >= EXTRA_FINE) {
  533.             st[0] = j * 0.4;
  534.         } else {
  535.             st[0] = j * 1.2;
  536.         }
  537.         st[1] = 0;
  538.         t2f(st);
  539.         v3f(s->w1);
  540.         st[1] = 1;
  541.         t2f(st);
  542.         } else {
  543.         v3f(s->w1);
  544.         }
  545.         v3f(s->w3);
  546.         s++;
  547.     }
  548.     endqstrip();
  549.  
  550.     /* end cap */
  551.     s--;
  552.     if (cap & 2) {
  553.         /* put cap on last segment of wall */
  554.         vsub(s->w0, (s-1)->w0, t1);
  555.         vnormal(t1); /* this is the approximate normal */
  556.         bgnqstrip();
  557.         n3f(t1);
  558.         v3f(s->w0);
  559.         v3f(s->w1);
  560.         v3f(s->w2);
  561.         v3f(s->w3);
  562.         endqstrip();
  563.     }
  564.         closeobj();
  565.     lastobject++;
  566.     w->top_obj = lastobject;
  567.     makeobj(w->top_obj);
  568.     /* top wall */
  569.     s = seg;
  570.     /*cpack(0x004f1024);*/
  571.     bgnqstrip();
  572.     for (j =0; j<= nstep; j++) {
  573.         n3f(s->n1);
  574.         v3f(s->w3);
  575.         v3f(s->w2);
  576.         s++;
  577.     }
  578.     endqstrip();
  579.     } else {
  580.     /* very low level of detail, create only a flat maze */
  581.     s = seg;
  582.     lastobject++;
  583.     w->top_obj = lastobject;
  584.     w->wall_obj = 0;
  585.     makeobj(w->top_obj);
  586.     /*cpack(0x004f1024);*/
  587.     bgnqstrip();
  588.     for (j =0; j<= nstep; j++) {
  589.         n3f(s->n1);
  590.         v3f(s->w1);
  591.         v3f(s->w0);
  592.         s++;
  593.     }
  594.     endqstrip();
  595.     }
  596.     closeobj();
  597. }
  598.  
  599. /*________________________________________________________________________
  600.  |
  601.  | build_maze - traverses the maze structure, and creates gl-objects
  602.  | 
  603.  | the gl-objects created are already spherical, no additional rotation,
  604.  | except the overall rotation of the sphere is needed.
  605.  | the Level of the maze is specified in the first parameter; the
  606.  | amount of detail present is varied with the 'Level-Of-Detail 
  607.  | parameter.
  608. */
  609.  
  610. void build_maze(int level, int lod) {
  611.  
  612.     int i, j, k;
  613.     float start[3];
  614.  
  615.     level_t    *levl_ptr;
  616.     center_t    *cent_ptr;
  617.     circle_t    *circ_ptr;
  618.     arc_t    *arc_ptr;
  619.     float    *wall_ptr;
  620.     float    *gap_ptr;
  621.     int        *capping_ptr;
  622.     int        ncirc, narc;
  623.     float    st_angle;
  624.     static int    prevlevel = -1;
  625.     static float stepangle[MAXCIRCLE] = {
  626.         0.314, 0.235, 0.196, 0.157079, 0.157079,
  627.         0.157079, 0.157079, 0.157079, 0.157079, 0.157079 };
  628.  
  629.  
  630.     levl_ptr = the_maze.levels+level;
  631.     the_level = *levl_ptr;
  632.     the_nodes = levl_ptr->nodes;
  633.     the_nnodes = levl_ptr->nnodes;
  634.     if (the_level.leveln != prevlevel) {
  635.     prevlevel = the_level.leveln;
  636.     }
  637.     cent_ptr = levl_ptr->centers;
  638.  
  639.     lastobject = 0;
  640.  
  641.     for (i = 0; i< levl_ptr->ncenters; i++) {
  642.     circ_ptr = cent_ptr->circles;
  643.     ncirc = cent_ptr->ncircles;
  644.     for (j=0; j< ncirc; j++) {
  645.         arc_ptr = circ_ptr->arcs;
  646.         narc = circ_ptr->narcs;
  647.         wall_ptr = circ_ptr->walls;
  648.         gap_ptr = circ_ptr->gaps;
  649.         capping_ptr = circ_ptr->cappings;        
  650.         st_angle = stepangle[j];
  651.         if (lod >= EXTRA_FINE) st_angle /= 3;
  652.         if (lod <= EXTRA_COARSE && lod >= WALLS_UP) st_angle *= 2;
  653.         vcopy(circ_ptr->start,  start);
  654.         for (k = 0 ; k< narc; k++) {
  655.         build_arc(cent_ptr->center_v, start, st_angle, 
  656.                 *wall_ptr++, *capping_ptr++, lod, arc_ptr, start);
  657.         arc_ptr++;
  658.         vrot_axis(start, cent_ptr->center_v, *gap_ptr++ , start);
  659.         } 
  660.         circ_ptr++;
  661.     }
  662.     cent_ptr++;
  663.     }
  664. }
  665.  
  666. #ifdef BUILDNODES
  667. static int add_node(const float *p, const int centnum) {
  668.     
  669.     int i;
  670.     for (i=0; i< the_nnodes; i++) {
  671.     if (the_nodes[i].cnt == -1) {
  672.         /* found an unused node, so use it */
  673.         vcopy(p, the_nodes[i].pos);
  674.         the_nodes[i].c[0] = -1;
  675.         the_nodes[i].c[1] = -1;
  676.         the_nodes[i].c[2] = -1;
  677.         the_nodes[i].c[3] = -1;
  678.         the_nodes[i].special.all = 0;
  679.         the_nodes[i].player = NULL;
  680.         the_nodes[i].cnt = 0;
  681.         return i;
  682.     }
  683.     }
  684.     vcopy(p, the_nodes[the_nnodes].pos);
  685.     the_nodes[the_nnodes].c[0] = -1;
  686.     the_nodes[the_nnodes].c[1] = -1;
  687.     the_nodes[the_nnodes].c[2] = -1;
  688.     the_nodes[the_nnodes].c[3] = -1;
  689.     the_nodes[the_nnodes].special.all = 0;
  690.     the_nodes[i].player = NULL;
  691.     the_nodes[the_nnodes].cnt = 0;
  692.     the_nnodes++;
  693.     return (the_nnodes-1);
  694. }
  695. #endif
  696.  
  697.  
  698. static void connect_nodes(const int n1, const int n2) {
  699.     int i, j;
  700.     
  701.     i=0;
  702.     if (n1 == n2) {
  703.     fprintf(stderr, "trying to connect node %d to itself\n", n1);
  704.     return;
  705.     }
  706.     while (i<4 && the_nodes[n1].c[i] >= 0) {
  707.     if ( the_nodes[n1].c[i] == n2)    /* check if already connected */
  708.         return;
  709.     i++;
  710.     }
  711.     if (i == 4) {
  712.     fprintf(stderr, 
  713.         "cannot make more connections to node %d (from %d)\n",  n1, n2);
  714.     return;
  715.     }
  716.     j=0;
  717.     while (j<4 && the_nodes[n2].c[j] >= 0) {
  718.     if ( the_nodes[n2].c[j] == n1)    /* check if already connected */
  719.         return;
  720.     j++;
  721.     }
  722.     if (j == 4) {
  723.     fprintf(stderr,
  724.         "cannot make more connections to node %d (from %d)\n", n2, n1);
  725.     return;
  726.     }
  727.     the_nodes[n1].c[i] = n2;
  728.     the_nodes[n2].c[j] = n1;
  729.     the_nodes[n1].cnt++;
  730.     the_nodes[n2].cnt++;
  731. }
  732.  
  733.  
  734. #ifdef BUILDNODES
  735. static void disconnect_nodes(const int n1, const int n2) {
  736.     int i, j;
  737.     
  738.     i=0;
  739.     while (i<4 && the_nodes[n1].c[i] != n2)
  740.     i++;
  741.     if (i==4) {
  742.     fprintf(stderr,
  743.         "trying to disconnect unconnected nodes %d, %d\n", n1, n2);
  744.     return;
  745.     }
  746.     while (i<3) {
  747.     the_nodes[n1].c[i] = the_nodes[n1].c[i+1];
  748.     i++;
  749.     }
  750.     the_nodes[n1].c[3] = -1;
  751.     the_nodes[n1].cnt --;
  752.     if (the_nodes[n1].cnt == 0)
  753.      the_nodes[n1].cnt = -1;
  754.     j = 0;
  755.     while (j<4 && the_nodes[n2].c[j] != n1)
  756.     j++;
  757.     if (j==4) {
  758.     fprintf(stderr,
  759.         "trying to disconnect unconnected nodes %d, %d\n", n1, n2);
  760.     return;    
  761.     }
  762.     while (j<3) {
  763.     the_nodes[n2].c[j] = the_nodes[n2].c[j+1];
  764.     j++;
  765.     }
  766.     the_nodes[n2].c[3] = -1;
  767.     the_nodes[n2].cnt --;
  768.     if (the_nodes[n2].cnt == 0)
  769.      the_nodes[n2].cnt = -1;
  770. }
  771. #endif
  772.  
  773.  
  774. int node_closest(float v[3], int nodenum, float mindist) {
  775.  
  776.     int j;
  777.     int mind;
  778.     float dist, dist2;
  779.     
  780.     dist = 10000;
  781.     mind = -1;
  782.     mindist = mindist * mindist;
  783.     for (j=0; j <the_nnodes; j++) {
  784.     if (the_nodes[j].cnt >= 0 && 
  785.         (dist2 = vdistance2(the_nodes[j].pos, v)) < dist &&
  786.         dist2 > mindist &&
  787.         nodenum != j && 
  788.         (nodenum < 0 ||
  789.         (the_nodes[nodenum].c[0] != j &&
  790.         the_nodes[nodenum].c[1] != j && 
  791.         the_nodes[nodenum].c[2] != j && 
  792.         the_nodes[nodenum].c[3] != j)) 
  793.         ) {
  794.         mind = j;
  795.         dist = dist2;
  796.     } 
  797.     }
  798.     return mind;
  799. }
  800.  
  801. #ifdef BUILDNODES
  802. static int node_length(int i) {
  803.     int n1, n2, cnt, prevnode;
  804.     
  805.     n1 = n2 = i;
  806.     cnt = 0;
  807.     prevnode = i;
  808.     while (the_nodes[n1].cnt > 0 && the_nodes[n1].c[0] != -1 &&
  809.          the_nodes[n1].c[0] != prevnode && the_nodes[n1].c[1] != prevnode &&
  810.          cnt < 100) {
  811.     cnt++;
  812.     prevnode = i;
  813.     n1 = the_nodes[n1].c[0];
  814.     }
  815.     prevnode = i;
  816.     while (the_nodes[n2].cnt > 0 && the_nodes[n2].c[1] != -1 &&
  817.         the_nodes[n2].c[1] != prevnode &&  the_nodes[n2].c[0] != prevnode &&
  818.         cnt < 100) {
  819.     cnt++;
  820.     prevnode = n2;
  821.     n2 = the_nodes[n2].c[1];
  822.     }
  823.     return (cnt);
  824. }
  825. #endif
  826.  
  827. #ifdef BUILDNODES
  828. static int check_node(float p[3], Matrix *m, int cent) {
  829.     
  830.     int i, j, k, gap;
  831.     
  832.     const float range = PI_DEPTH * 0.30;
  833.     float rs,  dist, alpha_s, alpha_p, prev_alpha;
  834.     center_t    *center_ptr;
  835.     circle_t    *circle_ptr;
  836.     float    *wall_ptr;
  837.     float    *gap_ptr;
  838.     float    pt[3], t1[3];
  839.     
  840.  
  841.     center_ptr = the_level.centers;
  842.     for (i=0; i < the_level.ncenters; i++ ) {
  843.     dist = vdistance(p, center_ptr->center_v);
  844.     /* check distance to points from other centers; no need
  845.      * to check for points that belong to the same center. also is
  846.      * within maximum radius of the center plus a bit extra.
  847.      */
  848.     if (i != cent && dist < center_ptr->radius + PI_DEPTH/2 ) {
  849.         /* point is possibly close enough transform point so it is in
  850.          * coordinate space relative to the center.
  851.          */
  852.         vtransform(p, m[i], pt);
  853.         /* start from outer circle because this is more likely
  854.          * to be close to a point from any other center.
  855.          */
  856.         circle_ptr = center_ptr->circles + center_ptr->ncircles -1;
  857.         
  858.         while (dist < circle_ptr->cradius + PI_DEPTH ) {
  859.         if (dist < circle_ptr->cradius - PI_DEPTH/2) {
  860.             circle_ptr--;
  861.             continue;
  862.         }
  863.         vtransform(circle_ptr->start, m[i], t1);
  864.         rs = sqrtf(SQR(t1[0]) + SQR(t1[1]));
  865.         alpha_s = atan2(t1[1],  t1[0]);
  866.         alpha_p = atan2(pt[1],  pt[0]);
  867.         if (alpha_s < 0) 
  868.             alpha_s += PI2;
  869.         if (alpha_p < 0)
  870.             alpha_p += PI2;
  871.         if (alpha_p < alpha_s)
  872.             alpha_p += PI2;
  873.         wall_ptr = circle_ptr->walls;
  874.         gap_ptr = circle_ptr->gaps;
  875.         /* find segment of circle (gap or wall) in which the
  876.          * point can be found.
  877.          */
  878.         for (j=0; j < circle_ptr->narcs; j++) {
  879.             prev_alpha = alpha_s;
  880.             alpha_s += *wall_ptr++;
  881.             gap = 0;
  882.             if (alpha_p < alpha_s) {
  883.             break;
  884.             }
  885.             prev_alpha = alpha_s;
  886.             alpha_s += *gap_ptr++;
  887.             gap = 1;
  888.             if (alpha_p < alpha_s) {
  889.             break;
  890.             }
  891.         }
  892.         /* if the point is in the sector of a gap, check the
  893.          * distance to the end points on both sides of the gap;
  894.          * else check distance to wall segment.
  895.          */
  896.         if (gap == 1) {
  897.             t1[0] = cos(prev_alpha) * rs;
  898.             t1[1] = sin(prev_alpha) * rs;
  899.             if (vdistance(t1, pt) < range)
  900.             return (0);
  901.             t1[0] = cos(alpha_s) * rs;
  902.             t1[1] = sin(alpha_s) * rs;
  903.             if (vdistance(t1, pt) < range) {
  904.             return (0);
  905.             }
  906.         } else {
  907.             t1[0] = cos(alpha_p) * rs;
  908.             t1[1] = sin(alpha_p) * rs;
  909.             if (vdistance(t1, pt) < range) {
  910.             return(0);
  911.             }
  912.         }
  913.         k--;
  914.         circle_ptr--;            
  915.         }
  916.     }
  917.     center_ptr++;
  918.     }
  919.     return (1);                /* point well enough outside any walls */
  920. }
  921. #endif
  922.  
  923. #ifdef BUILDNODES
  924. static int check_remove_node(int i) {
  925.     
  926.     int closest;
  927.     int j, bad, tmp;
  928.     float dist;
  929.     
  930.     if (the_nodes[i].cnt != 2 &&  the_nodes[i].cnt > 0) {
  931.     if (the_nodes[i].cnt == 1 && the_nodes[the_nodes[i].c[0]].cnt == 1) {
  932.         disconnect_nodes(i, the_nodes[i].c[0]);
  933.         return 1;
  934.     }
  935.     closest = node_closest(the_nodes[i].pos, i, 0.0);
  936.     dist = vdistance(the_nodes[closest].pos, the_nodes[i].pos);
  937.     if (dist > PI_DEPTH*0.375) {
  938.         return 0;
  939.     }
  940.     /* one of those points has to be removed; choose the one on the
  941.      * shortest path. This may not be optimal, but it works
  942.      */
  943.     if (node_length(i) < node_length(closest))
  944.         bad = i;
  945.     else
  946.         bad = closest;
  947.     j = 0;
  948.     while (j < the_nodes[bad].cnt) {
  949.         if ((tmp = the_nodes[bad].c[j]) != -1) {
  950.         
  951.         disconnect_nodes(bad, tmp);
  952.         (void) check_remove_node(tmp);
  953.         }
  954.         else 
  955.         j++;
  956.     }
  957.     return 1;
  958.     }
  959.     return 0;       
  960. }     
  961. #endif
  962.  
  963. /*________________________________________________________________________
  964.  |
  965.  | build_nodes - build a path that runs just between the walls
  966.  |
  967.  | given the data in the maze, construct a path that follows the
  968.  | space between the walls. This will be the path followed by the
  969.  | moving bits in the game.
  970.  | It builds the path for the current level stored in the_level.
  971. */
  972.  
  973. #ifdef BUILDNODES
  974. static void build_nodes(node_t *nodes) {
  975.  
  976.     /* initialy create all nodes lying on the path between all circles
  977.      * and add nodes lying on the gaps in the wall. Then check of none
  978.      * of those nodes is to close to a wall, is they are, remove those
  979.      * nodes from the list. In the next stage, all nodes that are close
  980.      * together are linked.
  981.      */
  982.     
  983.     float t1[3], t2[3], t3[3], t4[3];
  984.     Matrix *m;
  985.     int nstep, i, j, k, n, n1, n2;
  986.     float st_angle;
  987.     center_t *center_ptr;
  988.     circle_t *circle_ptr;
  989.     arc_t *arc_ptr;
  990.     float *wall_ptr;
  991.     float *gap_ptr;
  992.     int thisnode, accepted;
  993.     int narc;
  994.     int closest;
  995.     float dist;
  996.     int done, rejected;
  997.     
  998.     /* first stage generate the rotation matrices; used in other routines */
  999.     m = (Matrix *) alloca(the_level.ncenters * sizeof (Matrix));
  1000.     center_ptr = the_level.centers;
  1001.     for (i=0; i< the_level.ncenters; i++) {
  1002.     vcross(center_ptr->center_v, z_axis, t1);
  1003.     mmake_rot_axis(t1,
  1004.         -acos(vdot(center_ptr->center_v, z_axis)), m[i]);
  1005.     center_ptr++;
  1006.     }
  1007.  
  1008.     /* second stage: add the path in between the walls */
  1009.     center_ptr = the_level.centers;
  1010.     for (i=0; i < the_level.ncenters; i++) {
  1011.     circle_ptr = center_ptr->circles;
  1012.     for (j=0; j < center_ptr->ncircles-1 ; j++) {
  1013.         wall_ptr = circle_ptr->walls;
  1014.         gap_ptr = circle_ptr->gaps;
  1015.         
  1016.         st_angle = 0.5 / (j + 0.9508);
  1017.         vrot_axis(center_ptr->center_v, center_ptr->axis_v,
  1018.             (j+0.9508) * PI_DEPTH, t1 );
  1019.         vrot_axis(t1, center_ptr->center_v, circle_ptr->rotation,
  1020.             t1);
  1021.         nstep = PI2/st_angle + 0.5;        /* round to nearest int */
  1022.         st_angle = PI2/nstep;        /* and adjust step angle */
  1023.         vrot_axis(t1, center_ptr->center_v, st_angle,  t1); 
  1024.         /* remember the first nod in 'thisnode' so we can connect it
  1025.          * too the last node of the circle (when both are accepted)
  1026.          */
  1027.         if (check_node(t1, m, i)) {
  1028.         n = add_node(t1, i);
  1029.         accepted = n;
  1030.         thisnode = n;
  1031.         } else {
  1032.         accepted = -1;
  1033.         thisnode = -1;
  1034.         }
  1035.         for (k = 0; k < nstep-1; k++) {
  1036.         vrot_axis(t1, center_ptr->center_v, st_angle,  t1); 
  1037.         if (check_node(t1, m, i)) {
  1038.             n = add_node(t1, i);
  1039.             if (accepted >= 0) {
  1040.             connect_nodes(accepted, n);
  1041.             }
  1042.             accepted = n;
  1043.         } else {
  1044.             accepted = -1;
  1045.         }
  1046.         }
  1047.         if (thisnode >= 0 && accepted >=0 ) {
  1048.         connect_nodes(accepted, thisnode);
  1049.         }
  1050.         circle_ptr++;
  1051.     }
  1052.     center_ptr++;
  1053.     /* remove the nodes that are too close to other nodes */
  1054.     for (j=0; j< the_nnodes; j++) {
  1055.         if (the_nodes[j].cnt != 2 &&  the_nodes[j].cnt > 0) {
  1056.         (void)check_remove_node(j);
  1057.         }
  1058.     }
  1059.     }
  1060.     /* stage three: add nodes between the gaps */
  1061.     center_ptr = the_level.centers;
  1062.     for (i=0; i < the_level.ncenters; i++) {
  1063.     circle_ptr = center_ptr->circles;
  1064.     for (j=0; j < center_ptr->ncircles; j++) {
  1065.         wall_ptr = circle_ptr->walls;
  1066.         gap_ptr = circle_ptr->gaps;
  1067.         narc = circle_ptr->narcs;
  1068.         
  1069.         st_angle = 0.5 / (j+0.4508);    /* half the smallest gap size */
  1070.         /* process the gaps of the circle */ 
  1071.         vcopy(circle_ptr->start,  t1);
  1072.         vcross(center_ptr->center_v,t1, t2);
  1073.         vnormal(t2);
  1074.         vrot_axis (t1, t2, PI_DEPTH/5, t3);
  1075.         vrot_axis (t1, t2, - PI_DEPTH/5, t4);
  1076.         for (k = 0 ; k< narc; k++) {
  1077.         vrot_axis(t3, center_ptr->center_v, -st_angle, t1);
  1078.         vrot_axis(t4, center_ptr->center_v, -st_angle, t2);
  1079.         if (check_node(t1, m, i) && check_node(t2, m, i) &&
  1080.             vdistance(the_nodes[node_closest(t1, -1, 0.0001)].pos,t1) >
  1081.                 PI_DEPTH/6 &&
  1082.             vdistance(the_nodes[node_closest(t2, -1, 0.0001)].pos,t2) >
  1083.                 PI_DEPTH/6) {
  1084.             n1 = add_node(t1, i);
  1085.             rejected = check_remove_node(n1);
  1086.             if (!rejected) {
  1087.             n2 = add_node(t2, i);
  1088.             rejected = check_remove_node(n2);
  1089.             }
  1090.         } else {
  1091.             rejected = 1;
  1092.         }
  1093.         vrot_axis(t3, center_ptr->center_v, *wall_ptr,  t3);
  1094.         vrot_axis(t4, center_ptr->center_v, *wall_ptr++,  t4);
  1095.         if (rejected && *gap_ptr > st_angle * 2) {
  1096.             /* add an extra node */
  1097.             vrot_axis(t3, center_ptr->center_v, st_angle, t1);
  1098.             vrot_axis(t4, center_ptr->center_v, st_angle, t2);
  1099.             if (check_node(t1, m, i) && check_node(t2, m, i) &&
  1100.                 vdistance(the_nodes[node_closest(t1, -1, 0.0001)].pos,t1) >
  1101.                 PI_DEPTH/6 &&
  1102.                 vdistance(the_nodes[node_closest(t2, -1, 0.0001)].pos,t2) >
  1103.                 PI_DEPTH/6 ) {
  1104.             n1 = add_node(t1, i);
  1105.             rejected = check_remove_node(n1);
  1106.             if (!rejected) {
  1107.                 n2 = add_node(t2, i);
  1108.                 rejected = check_remove_node(n2);
  1109.             }    
  1110.             } else {
  1111.             rejected = 1;
  1112.             }
  1113.         }
  1114.         if (!rejected) {
  1115.             connect_nodes(n1, n2);
  1116.             closest = node_closest(the_nodes[n].pos, n1, PI_DEPTH*0.025);
  1117.             if (closest == -1) continue;
  1118.             dist = vdistance(the_nodes[closest].pos, the_nodes[n1].pos);
  1119.             if (dist < PI_DEPTH*0.60) {
  1120.             connect_nodes(closest, n1);
  1121.             }
  1122.             closest = node_closest(the_nodes[n2].pos, n2, PI_DEPTH*0.025);
  1123.             if (closest == -1) continue;
  1124.             dist = vdistance(the_nodes[closest].pos, the_nodes[n2].pos);
  1125.             if (dist < PI_DEPTH*0.6) {
  1126.             connect_nodes(closest, n2);
  1127.             }
  1128.         }
  1129.         vrot_axis(t3, center_ptr->center_v, *gap_ptr,  t3);
  1130.         vrot_axis(t4, center_ptr->center_v, *gap_ptr++,  t4);
  1131.         }
  1132.         circle_ptr++;
  1133.     }
  1134.     center_ptr++;
  1135.     }
  1136.     /* stage four: add nodes int the center of the circles */
  1137.     center_ptr = the_level.centers;
  1138.     for (i=0; i < the_level.ncenters; i++) {
  1139.         /* the center is always a node, so add it */
  1140.     add_node(center_ptr->center_v, i);
  1141.     center_ptr++;
  1142.     }
  1143.     
  1144.     /* stage five : connect loose ends that are close together */
  1145.     for(i=0; i< the_nnodes; i++) {
  1146.     if (the_nodes[i].cnt != 2 && the_nodes[i].cnt >= 0) {
  1147.         closest = node_closest(the_nodes[i].pos, i, PI_DEPTH*0.025);
  1148.         if (closest == -1) continue;
  1149.         dist = vdistance(the_nodes[closest].pos, the_nodes[i].pos);
  1150.         if (dist < PI_DEPTH*0.6) {
  1151.         connect_nodes(closest, i);
  1152.         }
  1153.     }
  1154.     }
  1155.  
  1156. }
  1157. #endif
  1158.  
  1159. #ifdef BUILDNODES        
  1160. void write_nodes(void) {
  1161.  
  1162.     FILE *f;
  1163.     static char fname[] = "nodes.out";
  1164.     int i,j ;
  1165.     
  1166.     f = fopen(fname, "w+");
  1167.     if (f == NULL) {
  1168.     fprintf(stderr, "failed to write nodes to %s\n",fname);
  1169.     end_sound();
  1170.     gexit();
  1171.     exit(1);
  1172.     }
  1173.     fprintf(f, "# number of nodes that follow is %d\n", the_nnodes);
  1174.     for (i = 0; i< the_nnodes; i++) {
  1175.     fprintf(f, "node(%4d, %3d", i, the_nodes[i].special.all);
  1176.     fprintf(f, ", %9.6f, %9.6f, %9.6f", the_nodes[i].pos[0],
  1177.         the_nodes[i].pos[1], the_nodes[i].pos[2]);
  1178.     for (j=0; j<the_nodes[i].cnt; j++) {
  1179.         fprintf(f,", %4d", the_nodes[i].c[j]);
  1180.     }
  1181.     fprintf(f,");\n");
  1182.     }
  1183.     fclose(f);
  1184. }
  1185. #endif
  1186.  
  1187. static void free_maze(maze_t *maze_ptr) {
  1188.     
  1189.     level_t    *level_ptr;
  1190.     center_t    *center_ptr;
  1191.     circle_t    *circle_ptr;
  1192.  
  1193.     level_ptr = maze_ptr->levels;
  1194.     while (maze_ptr->nlevels--) {
  1195.     center_ptr = level_ptr->centers;
  1196.     while (level_ptr->ncenters--) {
  1197.         /* free a center */
  1198.         circle_ptr = center_ptr->circles;
  1199.         while (center_ptr->ncircles--) {
  1200.         /* free an arc */
  1201.         free(circle_ptr->arcs);
  1202.         free(circle_ptr->walls);
  1203.         free(circle_ptr->gaps);
  1204.         free(circle_ptr->cappings);
  1205.         circle_ptr++;
  1206.         }
  1207.         free(center_ptr->circles);
  1208.         center_ptr++;
  1209.     }
  1210.     free(level_ptr->centers);
  1211.     free(level_ptr->nodes);
  1212.     level_ptr++;
  1213.     }
  1214.     free(maze_ptr->levels);
  1215.     
  1216. }
  1217.  
  1218. void free_arcs(void) {
  1219.   
  1220.     center_t    *center_ptr;
  1221.     circle_t    *circle_ptr;
  1222.     arc_t    *arc_ptr;
  1223.     int        i, j, k;
  1224.     
  1225.     center_ptr = the_level.centers;
  1226.     for (i = 0; i<the_level.ncenters; i++) {
  1227.     circle_ptr = center_ptr->circles;
  1228.     for (j = 0; j < center_ptr->ncircles; j++) {
  1229.         arc_ptr = circle_ptr->arcs;
  1230.         for (k = 0; k < circle_ptr->narcs; k++) {
  1231.         if (arc_ptr->wall_obj != 0) {
  1232.             if (!isobj(arc_ptr->wall_obj)) {
  1233.             fprintf(stderr, "buggy object; ignored\n");
  1234.             } else {
  1235.             delobj (arc_ptr->wall_obj);
  1236.             } 
  1237.         }
  1238.         if (!isobj(arc_ptr->top_obj)) {
  1239.             fprintf(stderr, "buggy object; ignored\n");
  1240.         } else {
  1241.             delobj (arc_ptr->top_obj);
  1242.         }
  1243.         arc_ptr++;
  1244.         }
  1245.         circle_ptr++;
  1246.     }
  1247.     center_ptr++;
  1248.     }
  1249. }
  1250.  
  1251. extern int mouse_dead;    
  1252.  
  1253.  
  1254. /*_____________________________________________________________________________
  1255.  |
  1256.  | draw_maze - show all the walls of the maze
  1257.  |
  1258.  | a trick is used to make the look darker on the shadow side
  1259.  | of the planet
  1260.  |
  1261. */
  1262.  
  1263. void draw_maze(const Matrix m, int zbuf) {
  1264.     /* m is the rotation matrix , im its inverse ;
  1265.      * zbuf indicates whether the zbuffer is on
  1266.      */
  1267.  
  1268.     int i, j, k;
  1269.     int currmat;
  1270.     float c;
  1271.     int ncenter, ncirc, narc;
  1272.     center_t *center_ptr;
  1273.     circle_t *circle_ptr;
  1274.     arc_t    *arc_ptr;
  1275.     float   t1[3];
  1276.     float   l1[5]; float l2[5];
  1277.     Matrix mm;
  1278.     
  1279.     /* draw the walls */
  1280.     currmat = 0;
  1281.     pushmatrix();
  1282.     pushmatrix();
  1283.     multmatrix(m);
  1284. #ifdef STRANGE_LIGHT
  1285.     lmbind(LIGHT0,4);
  1286. #endif
  1287.     /*shademodel(GOURAUD);*/
  1288.     lmcolor(LMC_SPECULAR);
  1289.     ncenter = the_level.ncenters;
  1290.     center_ptr = the_level.centers;
  1291.     l2[0] = l2[1] = l2[2] = l2[3] = l2[4] = -1; 
  1292.     if (Lod >= TEXTURE_MAPS && can_do_textures) {
  1293.     tevbind(TV_ENV0, 1);
  1294.     texbind(TX_TEXTURE_0, 2);
  1295.     texgen(TX_S, TG_OFF, NULL);
  1296.     texgen(TX_T, TG_OFF, NULL);
  1297.     }
  1298.     /* check if walls are defined */
  1299.     if (center_ptr->circles->arcs->wall_obj != 0 ) {
  1300.     for (i= 0; i< ncenter; i++) {
  1301.         vtransform( center_ptr->center_v, m, t1);
  1302. #ifdef STRANGE_LIGHT        
  1303.         if (t1[1] < 0) {
  1304.         if (currmat != 3) {
  1305.             currmat = 3;
  1306.             lmbind(MATERIAL, 3);
  1307.         }
  1308.         } else {
  1309.         if (currmat != 2) {
  1310.             currmat = 2;
  1311.             lmbind(MATERIAL, 2);
  1312.         }
  1313.         }
  1314. #else
  1315.         if (currmat != 2) {
  1316.         currmat = 2;
  1317.         lmbind(MATERIAL, 2);
  1318.         }
  1319. #endif    
  1320.         ncirc = center_ptr->ncircles;
  1321.         /* trick to make things darker in the shadow of the sphere */
  1322.         if (t1[1] < 0 ) {
  1323.         c = 1.0+t1[1];
  1324.         if (c < 0) c = 0;
  1325.         } else  c = 1.0;
  1326.         l1[0] = LCOLOR;
  1327.         l1[1] = 0.7 * c; l1[2] = c; l1[3] = c;
  1328.         l1[4] = LMNULL;
  1329.         if (l1[0] != l2[0] || l1[1] != l2[1] || l1[2] != l2[2] ) {
  1330.         lmdef(DEFLIGHT,1,sizeof(l1), l1);
  1331.         l2[0] = l1[0];
  1332.         l2[1] = l1[1];
  1333.         l2[2] = l1[2];
  1334.         }
  1335.         circle_ptr = center_ptr->circles+ncirc-1;
  1336.         for (j=0; j < ncirc-1; j++) {
  1337.         if (t1[2]<0 && circle_ptr->cradius*sqrtf(1-SQR(t1[2]))
  1338.              < -t1[2]-EXTRA)
  1339.             break;
  1340.         narc = circle_ptr->narcs;
  1341.         arc_ptr = circle_ptr->arcs;
  1342.         for (k = 0; k < narc; k++) {
  1343.             callobj ((*arc_ptr++).wall_obj);
  1344.         }
  1345.         circle_ptr--;
  1346.         }
  1347.         center_ptr++;
  1348.     }
  1349.     }
  1350.     if (Lod >= TEXTURE_MAPS && can_do_textures) {
  1351.     texbind(TX_TEXTURE_0, 0);
  1352.     }
  1353.     getmatrix(mm);
  1354.     popmatrix();
  1355.     c = 1.0;
  1356.     l1[0] = LCOLOR;
  1357.     l1[1] = 0.7 * c; l1[2] = c; l1[3] = c;
  1358.     l1[4] = LMNULL;
  1359.     if (l1[0] != l2[0] || l1[1] != l2[1] || l1[2] != l2[2] ) {
  1360.     lmdef(DEFLIGHT,1,sizeof(l1), l1);
  1361.     l2[0] = l1[0];
  1362.     l2[1] = l1[1];
  1363.     l2[2] = l1[2];
  1364.     }
  1365.     lmbind(LIGHT0, 1);
  1366.     loadmatrix(mm);   
  1367.     /* draw the top of the walls */
  1368.     if (Lod < WALLS_UP && mouse_dead == 0) {
  1369.     zbuffer (FALSE);
  1370.     }
  1371.     lmbind(MATERIAL,4);
  1372.     center_ptr = the_level.centers;
  1373.     for (i= 0; i< ncenter; i++) {
  1374.     ncirc = center_ptr->ncircles;
  1375.     circle_ptr = center_ptr->circles+ncirc-1;
  1376.     vtransform( center_ptr->center_v, m, t1);
  1377.     for (j=0; j < ncirc-1; j++) {
  1378.         if (t1[2]<0 && circle_ptr->cradius*sqrtf(1-SQR(t1[2]))
  1379.             < -t1[2]-EXTRA)
  1380.         break;
  1381.         narc = circle_ptr->narcs;
  1382.         arc_ptr = circle_ptr->arcs;
  1383.         for (k = 0; k < narc; k++) {
  1384.             callobj ((*arc_ptr++).top_obj);
  1385.         }
  1386.         circle_ptr--;
  1387.     }
  1388.     center_ptr++;
  1389.     }
  1390.     lmcolor(LMC_COLOR);
  1391.     if (Lod < WALLS_UP) {
  1392.     zbuffer (zbuf);
  1393.     }
  1394.  
  1395. #ifdef SHOWPATH    
  1396.     /* just for debugging, plot the nodes */
  1397.     {
  1398.     float t1[3];
  1399.     
  1400.     linewidth(2);
  1401.     color(WHITE);
  1402.     for (i=0; i< the_nnodes; i++) {
  1403.         if (the_nodes[i].cnt >= 0) {
  1404.         vcopy(the_nodes[i].pos,  t1);
  1405.         bgnline();      
  1406.         vscalar(t1, 1.002);
  1407.         v3f(t1);
  1408.         vscalar(t1, 1.03);
  1409.         v3f(t1);
  1410.         if (the_nodes[i].c[0] != -1 &&
  1411.             the_nodes[the_nodes[i].c[0]].cnt > 0)
  1412.             v3f(the_nodes[the_nodes[i].c[0]].pos);
  1413.         if (the_nodes[i].c[1] != -1 &&
  1414.             the_nodes[the_nodes[i].c[1]].cnt > 0) {
  1415.             v3f(t1);
  1416.             v3f(the_nodes[the_nodes[i].c[1]].pos);
  1417.         }
  1418.         if (the_nodes[i].c[2] != -1 &&
  1419.             the_nodes[the_nodes[i].c[2]].cnt > 0) {
  1420.             v3f(t1);
  1421.             v3f(the_nodes[the_nodes[i].c[2]].pos);
  1422.         }
  1423.         if (the_nodes[i].c[3] != -1 &&
  1424.             the_nodes[the_nodes[i].c[3]].cnt > 0) {
  1425.             v3f(t1);
  1426.             v3f(the_nodes[the_nodes[i].c[3]].pos);
  1427.         }
  1428.         endline();
  1429.         }
  1430.     }
  1431.     }
  1432. #endif
  1433.     popmatrix();
  1434. }
  1435.  
  1436.  
  1437.  
  1438.